/*
 * 结合应用层来分析一下semaphore的原理
*/

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/semaphore.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/of_device.h>

struct semaphore sema;

struct class *driver_test_class;
dev_t dev;
struct cdev *cdev;
    
/*
 * 要理解down、down_interruptible、down_killable、down_timeout
 * 需要明白TASK_INTERRUPTIBLE、TASK_KILLABLE、TASK_UNINTERRUPTIBLE的区别
*/
static int semaphore_open(struct inode * inode, struct file * filp)
{
    int ret;

    // If the sleep is interrupted by a signal  ==>  被信号打断
    // if (ret = down_interruptible(&sema))
    //     printk("%s: flag 1, ret = %d\n", __func__, ret);
    // if (ret = down_interruptible(&sema))
    //     printk("%s: flag 2, ret = %d\n", __func__, ret);

    // If the sleep is interrupted by a fatal signal  ==>  被致命的信号打断
    if (ret = down_killable(&sema))
        printk("%s: flag 1, ret = %d\n", __func__, ret);
    if (ret = down_killable(&sema))
        printk("%s: flag 2, ret = %d\n", __func__, ret);

    // 阻塞 信号不可中断
    // down(&sema);   // 没有返回值
    // down(&sema);   // 没有返回值

    return 0;
}

const struct file_operations my_ops = {
    .open = semaphore_open,
};

static int __init semaphore_init(void)
{
    struct device *drv_device = NULL;

    printk("%s...\n", __func__);

    driver_test_class = class_create(THIS_MODULE, "my_class");
    alloc_chrdev_region(&dev, 10, 1, "my_driver");
    cdev = cdev_alloc();
    cdev->owner = THIS_MODULE;
    cdev->ops = &my_ops;
    cdev_add(cdev, dev, 1);
    drv_device = device_create(driver_test_class, NULL, dev, NULL, "semaphore_app");

    sema_init(&sema, 1);

    return 0;
}


static void __exit semaphore_exit(void)
{
    printk("%s...\n", __func__);

    device_destroy(driver_test_class, dev);
    class_destroy(driver_test_class);

    cdev_del(cdev);
    unregister_chrdev_region(cdev->dev, 1);
}

module_init(semaphore_init);
module_exit(semaphore_exit);
MODULE_LICENSE("Dual BSD/GPL");
